/**
 * 所有版权归 广西梧州 陈锦韬 所有
 *
 * @Title: FeignDecodeBean
 * @Package com.rx.core.bean
 * @Description: 解码替换
 * @author: 陈锦韬
 * @date: 2020\4\19 0019
 * @version V1.0
 * @Copyright: 2020 陈锦韬  All rights reserved.
 */
package com.rx.core.bean;


import com.rx.core.base.RxBaseData;
import com.rx.core.base.RxResponse;
import com.rx.core.enm.RESULT_CODE;
import com.rx.core.util.EmptyChecker;
import com.rx.core.util.RxUtil;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.Optional;

/**
 * @author: Administrator
 * @Description: 解码替换
 * @date: 2020\4\19 0019
 */
@Configuration
public class FeignDecodeBean {

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Decoder decoder() {
        return new DefaultDecoder(
                new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
    }

    @Slf4j
    public static class DefaultDecoder implements Decoder {
        final Decoder delegate;

        public DefaultDecoder(Decoder delegate) {
            Objects.requireNonNull(delegate, "Decoder must not be null. ");
            this.delegate = delegate;
        }

        boolean classYes(Class<?> cls){
            if (EmptyChecker.isEmpty(cls)){
                return false;
            }
            Class<?> clss = cls;
            while (clss != null){
                if (RxBaseData.class.equals(clss)){
                    return true;
                }
                clss = clss.getSuperclass();
            }
            return false;
        }

        @Override
        public Object decode(Response response, Type type) throws IOException, DecodeException,FeignException {
            if (!isOptional(type)) {
                Class<?> cls = (type instanceof Class ? (Class<?>) type : null);
                if (classYes(cls)){
                    RxResponse rxResponse = (RxResponse)delegate.decode(response, RxResponse.class);
                    if (EmptyChecker.isEmpty(rxResponse)){
                        throw new DecodeException(900,"返回出错",response.request());
                    }

                    log.info("返回JSON:" + rxResponse.toString());

                    if (!RESULT_CODE.OK.getCode().equals(rxResponse.getResultCode())){
                        throw new DecodeException(901,"返回出错.[" + rxResponse.getResultCode() + "]" + rxResponse.getResultMessage(),response.request());
                    }

                    return RxUtil.ConvertUtil.objectConvert(rxResponse.getResultData(),cls);
                }
                return delegate.decode(response, type);
            }
            if (response.status() == 404 || response.status() == 204) {
                return Optional.empty();
            }
            Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class);

            return Optional.ofNullable(delegate.decode(response, enclosedType));
        }

        static boolean isOptional(Type type) {
            if (!(type instanceof ParameterizedType)) {
                return false;
            }
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getRawType().equals(Optional.class);
        }

    }
}
